﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace ScriptCompare
{
    public abstract class ScriptSectionBase : IScriptSection, IEquatable<IScriptSection>
    {
        public const int RequiredNameMatchPercent = 80;

        private readonly List<IScriptSection> _childrenSections = new List<IScriptSection>();

        private readonly string _name;
        private readonly ScriptSectionType _sectionType = ScriptSectionType.Global;
        private readonly bool _requiresOrderedComparison = false;

        protected readonly LineCollectionBase _sectionLines;
        protected bool _sectionHighlighted = false;

        protected ScriptSectionBase(string ssName, ScriptSectionType ssType, IEnumerable<ScriptLine> lines, bool reqOrderedComp)
        {
            _name = ssName;
            _sectionType = ssType;
            _requiresOrderedComparison = reqOrderedComp;

            if (reqOrderedComp)
                _sectionLines = new OrderedLineCollection(lines);
            else
                _sectionLines = new UnorderedLineCollection(lines);            
        }

        #region IScriptSection Members

        public string SectionName
        {
            get { return _name; }
        }

        public ScriptSectionType SectionType
        {
            get { return _sectionType; }
        }

        public bool SectionRequiresOrder
        {
            get { return _requiresOrderedComparison; }
        }

        public bool SectionHighlighted
        {
            get { return _sectionHighlighted; }
        }

        public ILineCollection SectionContents
        {
            get { return (_sectionLines); }
            protected set
            {
                if (value != null)
                {
                    _sectionLines.ReplaceLines(value.Lines);
                }
            }
        }

        public IList<IScriptSection> GetSectionChildren()
        {
            return (_childrenSections.OrderBy(c => c.SectionName).ToList().AsReadOnly());
        }

        public void AddChildSection(IScriptSection child)
        {
            if (!_childrenSections.Contains(child))
                _childrenSections.Add(child);
        }

        public void RemoveChildSection(IScriptSection child)
        {
            if (_childrenSections.Contains(child))
                _childrenSections.Remove(child);
        }

        public bool IsSectionCommented()
        {
            bool isCommented = true;

            foreach (ScriptLine line in _sectionLines.Lines)
            {
                if (line.IsEmpty)
                    continue;
                else if (!line.IsComment)
                {
                    isCommented = false;
                    break;
                }
            }

            return (isCommented);
        }

        public IScriptSection CreateEmptySection()
        {
            // Use the static method to build up a collection of empty children
            return (CreateEmptySection(this));
        }

        #endregion

        protected abstract ScriptSectionBase CreateEmpty(ILineCollection emptyLines);

        #region IEquatable<IScriptSection> Members

        public bool Equals(IScriptSection other)
        {
            if (other.SectionType == this.SectionType)
            {
                // Check for exact name match
                if (other.SectionName.Trim().ToLower() ==
                    this.SectionName.Trim().ToLower())
                {
                    return true;
                }
                else if ((100 - StringUtilities.CalculateDistance(other.SectionName, this.SectionName)) >= RequiredNameMatchPercent)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
                return false;
        }

        #endregion


        private static IScriptSection CreateEmptySection(IScriptSection parent)
        {
            // Check to see if the parent has children
            if (parent.GetSectionChildren().Count > 0)
            {
                // Go through each child and create a new empty section for the parent
                foreach (var child in parent.GetSectionChildren())
                {
                    parent.AddChildSection(CreateEmptySection(child));
                }

                // Replace the parent's line collection
                parent.SectionContents = parent.SectionContents.CreateBlank();

                // Return the parent
                return (parent);
            }
            // Otherwise, no children...
            else
            {
                // Get the parent as a section base
                ScriptSectionBase p = parent as ScriptSectionBase;

                // Create an empty LineCollection from the parent
                var lc = p.SectionContents.CreateBlank();

                // Create an empty child
                ScriptSectionBase child = p.CreateEmpty(lc);

                // Return the child
                return (child);
            }
        }
    }
}
